#include <omp.h>
#include <unistd.h>

#include <filesystem>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <thread>
#include <vector>

namespace fs = std::filesystem;
using namespace std;

const string kOutputDir = "./output";
const string lat_start = " lat=\"";
const string lon_start = "\" lon=\"";
const string lon_end = "\">";

void process_file(fs::path this_path, fs::path output_file) {
  ofstream ofs;
  ifstream ifs;
  ofs.open(output_file);
  if (ofs.fail()) {
    cout << "can't open file " << output_file << endl;
    std::abort();
  }

  cout << this_path << endl;
  cout << output_file << endl;

  for (const auto& entry : fs::directory_iterator(this_path)) {
    if (entry.status().type() == fs::file_type::regular) {
      auto this_file = entry.path();
      ifs.open(this_file);

      string line;
      while (getline(ifs, line)) {
        std::regex reg(".*<trkpt lat=.*lon=.*>.*");

        if (std::regex_match(line, reg)) {
          int i = line.find(lat_start);
          int j = line.find(lon_start);
          int k = line.find(lon_end);

          auto lat_i = i + lat_start.size();
          auto lat_str = line.substr(lat_i, j - lat_i);

          auto lon_i = j + lon_start.size();
          auto lon_str = line.substr(lon_i, k - lon_i);

          ofs << lat_str << " " << lon_str << endl;
        }
      }

      ifs.close();
    } else {
      cout << "Error file..." << endl;
      std::abort();
    }
  }

  ofs.close();
}

void process(fs::path path, fs::path output) {
  vector<fs::path> all_path;

  for (const auto& entry : fs::directory_iterator(path)) {
    if (fs::is_directory(entry.status())) {
      all_path.push_back(entry.path());
      // process_file(entry.path());
    } else {
      cout << "Error 2nd level directory..." << endl;
      std::abort();
    }
  }

  int n = all_path.size();

#pragma omp parallel for
  for (int i = 0; i < n; ++i) {
    auto this_path = all_path[i];
    auto this_output = output;
    this_output.append(output.filename().string() +
                       this_path.filename().string() + ".txt");

    process_file(this_path, this_output);
  }
}

int main(int argc, char* argv[]) {
  if (argc < 2) {
    cout << "Enter the base directory..." << endl;
    std::abort();
  }

  string base_path = argv[1];
  if (!fs::exists(base_path)) {
    cout << "Error base directory..." << endl;
    std::abort();
  }

  fs::path output_dir(kOutputDir);

  if (!fs::exists(output_dir)) {
    fs::create_directory(output_dir);
  }

  for (const auto& entry : fs::directory_iterator(base_path)) {
    if (fs::is_directory(entry.status())) {
      auto this_path = entry.path();
      auto this_output_dir = output_dir;
      this_output_dir.append(entry.path().filename().string());

      if (!fs::exists(this_output_dir)) {
        fs::create_directory(this_output_dir);
      }

      process(this_path, this_output_dir);

    } else {
      cout << "Error 1st level directory..." << endl;
      std::abort();
    }
  }

  return 0;
}